﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;
using SHomeWorkshop.LunarMind.ConceptWidgets;
using SHomeWorkshop.LunarMind;

namespace SHomeWorkshop.LunarConcept.Controls
{
    /// <summary>
    /// 创建时间：2015年10月8日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：用以承载各Widget的编辑器。
    /// 基本结构：总封装编辑器（EditorManager）→本编辑器（PageEditor）→
    ///           外层容器（baseCanvas)→控制模拟物（如画线时的显示虚线）、内容器（mainCanvas）→各部件。
    ///           
    ///           真正用以放置部件的是内容器（mainCanvas）。
    ///           ——本类继承自Decorator，内部嵌入了个外层容器（baseCanvas），外层容器内部又嵌入了一个内容器（mainCanvas）。
    ///           
    /// ★★注意：作为基本功能类，此类与EdiorManager类一样，都不应直接调用“注册修改项”的代码。
    ///           ——所有“修改项”的注册都应由“自定义命令”的Execute()方法来调用。
    /// </summary>
    public class PageEditorReader : AdornerDecorator
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]
        /// </summary>
        static PageEditorReader()
        {
            defPaperInfo = PaperInfo.GetPaperInfo("A4");
        }

        private Brush assistGridStroke = Brushes.Blue;


        public static PaperInfo defPaperInfo;
        
        /// <summary>
        /// PageEditorReader类的构造方法。
        /// </summary>
        public PageEditorReader()
        {
            this.baseCanvas.Background = Brushes.BurlyWood;
            this.HorizontalAlignment = HorizontalAlignment.Center;
            this.VerticalAlignment = VerticalAlignment.Center;
            this.Margin = PageEditorReader.baseMargin;

            //注意顺序，避免再设置ZIndex。

            //添加页眉矩形
            this.baseCanvas.Children.Add(this.pageLeftSideRectangle);

            //添加页脚矩形
            this.baseCanvas.Children.Add(this.pageRightSideRectangle);
            
            this.baseCanvas.Children.Add(this.pagination);

            this.baseCanvas.Children.Add(this.tbPageTitle);

            //添加页面编辑区矩形。
            editorAdornerDecorator = new AdornerDecorator();
            this.editAreaRectangle.Stroke = this.editAreaRectangle.Fill = Brushes.Transparent;//都透明即可。
            editorAdornerDecorator.Child = this.editAreaRectangle;
            this.baseCanvas.Children.Add(editorAdornerDecorator);

            this.editAreaAdorner = new PageEditAreaGridAdorner(this.editAreaRectangle, this);
            editorAdornerDecorator.AdornerLayer.Add(this.editAreaAdorner);

            #region 完成容器嵌套和尺寸绑定
            this.Child = this.baseCanvas;

            this.baseCanvas.Children.Add(this.mainCanvas);

            Binding windthBinding = new Binding("Width");
            windthBinding.Source = baseCanvas;
            mainCanvas.SetBinding(Canvas.WidthProperty, windthBinding);

            Binding heightBinding = new Binding("Height");
            heightBinding.Source = baseCanvas;
            mainCanvas.SetBinding(Canvas.HeightProperty, heightBinding);

            this.RefreshPaperDirectionAndSize();
            #endregion

            //PageEditorReader类构造方法的其它初始化操作。

            this.baseCanvas.SizeChanged += new SizeChangedEventHandler(baseCanvas_SizeChanged);

            //注意添加的顺序。用于模拟插入线条位置的Line、模拟选定框的Rectangle都要最后添加，
            //这样才能浮在mainCanvas上面（以免去设置ZIndex）。
            
        }

        #endregion

        #region 字段与属性===================================================================================================



        /// <summary>
        /// 表示编辑区的边界线。
        /// </summary>
        private Rectangle editAreaRectangle = new Rectangle()
        {
            Fill = null,
            StrokeThickness = 1,
            SnapsToDevicePixels = true,
            StrokeDashArray = LineDashType.dotCollection,
            Opacity = 0.8,
        };

        private string commentText = string.Empty;
        /// <summary>
        /// [读写]页面备注文本。
        /// </summary>
        public string CommentText
        {
            get { return this.commentText; }
            set
            {
                this.commentText = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.CommentTextTag, XmlTools.ReplaceXmlChars(value));
                }
            }
        }
        
        /// <summary>
        /// 最外层的Canvas，里面会有些部件浮动在内部mainCanvas的表层，用于进行一些操作。（例如：几个控制点）
        /// </summary>
        private Canvas baseCanvas = new Canvas() { ClipToBounds = true };
        /// <summary>
        /// [只读]基面板。导出图像时要用到。
        /// </summary>
        public Canvas BaseCanvas
        {
            get { return baseCanvas; }
        }

        /// <summary>
        /// [静态字段]表示页面外部基本的空缺。
        /// </summary>
        private static Thickness baseMargin = new Thickness(0);
        
        /// <summary>
        /// [只读]返回边框的四边宽度。
        /// </summary>
        public Thickness BorderThickness
        {
            get { return new Thickness(0); }
        }

        /// <summary>
        /// [只读]公开mainCanvas的Children。
        /// </summary>
        public UIElementCollection Children
        {
            get
            {
                return this.mainCanvas.Children;
            }
        }

        private Rect editArea = new Rect();
        /// <summary>
        /// [只读]编辑区尺寸。
        /// </summary>
        public Rect EditArea
        {
            get { return editArea; }
        }
        
        private string id;
        /// <summary>
        /// [只读]每个编辑器都有的唯一标识符。
        /// </summary>
        public string Id
        {
            get { return id; }
        }
        
        /// <summary>
        /// 用以承载部件的主Canvas。
        /// </summary>
        private Canvas mainCanvas = new Canvas()
        {
            Background = Brushes.Transparent,
        };

        /// <summary>
        /// [只写]只用于触发MainSelectedWidgetChanged事件。
        /// </summary>
        public Widget MainSelectedWidget
        {
            set { OnMainSelectedWidgetChanged(this, new MainSelectedWidgetChangedEventArgs(value)); }
        }
        
        /// <summary>
        /// [只读]主要部件承载区。
        /// </summary>
        public Canvas MainCanvas
        {
            get
            {
                return this.mainCanvas;
            }
        }
        
        private Brush pageBackground = Brushes.White;
        /// <summary>
        /// [只读]表示页面的背景色。
        /// </summary>
        public Brush PageBackground
        {
            get { return pageBackground; }
            set
            {
                pageBackground = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.PageBackground,
                        Tools.BrushManager.GetEnglishName(pageBackground));
                    RefreshPageBackground();
                }
            }
        }

        private Rectangle pageLeftSideRectangle = new Rectangle()
        {
            Stroke = Brushes.Transparent,
            Fill = Brushes.Transparent,
            StrokeThickness = 0,
        };

        private Rectangle pageRightSideRectangle = new Rectangle()
        {
            Stroke = Brushes.Transparent,
            Fill = Brushes.Transparent,
            StrokeThickness = 0,
        };

        private Brush pageRightSideBackColor = Brushes.Transparent;
        /// <summary>
        /// [读写]整个页脚（而不是仅页脚文本所在区域）的背景色。
        /// </summary>
        public Brush PageRightSideBackColor
        {
            get { return pageRightSideBackColor; }
            set
            {
                pageRightSideBackColor = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.PageRightSideBackColorTag, Tools.BrushManager.GetName(value));
                }

                this.pageRightSideRectangle.Fill = value;
            }
        }

        private Brush pageLeftSideBackColor = Brushes.Transparent;
        /// <summary>
        /// [读写]整个页眉（而不是仅页眉文本所在区域）的背景色。
        /// </summary>
        public Brush PageLeftSideBackColor
        {
            get { return pageLeftSideBackColor; }
            set
            {
                pageLeftSideBackColor = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.PageLeftSideBackColorTag, Tools.BrushManager.GetName(value));
                }

                this.pageLeftSideRectangle.Fill = value;
            }
        }
        
        private TextBlock tbPageTitle = new TextBlock()
        {
            Foreground = Brushes.DarkGray,
        };

        /// <summary>
        /// [读写]返回页标题文本块的文本。
        /// </summary>
        public String PageTitle
        {
            get { return tbPageTitle.Text; }
            set
            {
                if (value == null)
                {
                    tbPageTitle.Text = string.Empty;
                    if (this.xmlData != null)
                    {
                        this.xmlData.SetAttribute(XmlTags.PageTitleTag, string.Empty);
                    }
                }
                else
                {
                    tbPageTitle.Text = value;
                    if (this.xmlData != null)
                    {
                        this.xmlData.SetAttribute(XmlTags.PageTitleTag, value);
                    }
                }

                RefreshPageTitleLocation();
            }
        }

        private TextBlock pagination = new TextBlock()
        {
            Foreground = Brushes.DarkSlateBlue,
        };
        /// <summary>
        /// [只读]显示页码号的文本块。
        /// </summary>
        public TextBlock Pagination
        {
            get { return pagination; }
        }

        private PaperInfo paperSize = PaperInfo.GetPaperInfo("A4");
        /// <summary>
        /// 纸张尺寸。
        /// ——按支持的纸型名称来获取（支持的纸型包括：A0~A10,B0~B10）。
        /// <example>PaperInfo pi = PaperInfo.GetPaperInfo("A4");</example>
        /// </summary>
        public PaperInfo PaperSize
        {
            get { return paperSize; }
            set
            {
                paperSize = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.PaperSizeTag,
                        paperSize.PaperTypeName);
                }

                RefreshPaperDirectionAndSize();
            }
        }

        private int pageLongSideMultiple = 1;
        /// <summary>
        /// [读写]页面长边扩展倍数。最终呈现的页面长边尺寸由PageSize中指定的纸型的长边乘以此值决定。默认值为1。
        /// </summary>
        public int PageLongSideMultiple
        {
            get { return this.pageLongSideMultiple; }
            set
            {
                this.pageLongSideMultiple = value;

                //if (this.xmlData != null)
                //{
                //    this.xmlData.SetAttribute(XmlTags.PageLongSideMultipleTag,
                //        this.pageLongSideMultiple.ToString());
                //}

                RefreshPaperDirectionAndSize();
            }
        }

        private int pageShortSideMultiple = 1;
        /// <summary>
        /// [读写]页面短边扩展倍数。最终呈现的页面短边尺寸由PageSize中指定的纸型的短边乘以此值决定。默认值为1。
        /// </summary>
        public int PageShortSideMultiple
        {
            get { return this.pageShortSideMultiple; }
            set
            {
                this.pageShortSideMultiple = value;

                //if (this.xmlData != null)
                //{
                //    this.xmlData.SetAttribute(XmlTags.PageShortSideMultipleTag,
                //        this.pageShortSideMultiple.ToString());
                //}

                RefreshPaperDirectionAndSize();
            }
        }

        private Orientation paperDirection = Orientation.Vertical;
        /// <summary>
        /// 页面的方向。
        /// </summary>
        public Orientation PaperDirection
        {
            get
            {
                return paperDirection;
            }

            set
            {
                paperDirection = value;

                //if (this.xmlData != null)
                //{
                //    this.xmlData.SetAttribute(XmlTags.PaperDirectionTag,
                //        paperDirection.ToString());
                //}

                RefreshPaperDirectionAndSize();
            }
        }
        
        /// <summary>
        /// [只读]取当前页面节点的“WidgetSet”子节点。意外情况下可能返回null。一般不应出现此情况。
        /// </summary>
        public XmlNode WidgetSetNode
        {
            get
            {
                if (this.xmlData == null) return null;

                XmlNode widgetSetNode = this.xmlData.SelectSingleNode(XmlTags.WidgetSetTag);
                if (widgetSetNode == null)
                {
                    widgetSetNode = this.xmlData.AppendXmlAsChild("<" + XmlTags.WidgetSetTag + " />");
                }

                return widgetSetNode;
            }
        }

        private XmlNode xmlData;

        /// <summary>
        /// 用以生成当前编辑器中所有内容的Xml数据节点。
        /// </summary>
        public XmlNode XmlData
        {
            get { return xmlData; }
            set
            {
                xmlData = value;
                this.Build();
            }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 将Widget添加到mainCanvas中。
        /// </summary>
        /// <param name="sw">要添加的Widget。</param>
        /// <returns></returns>
        public int AddWidget(Widgets.Widget w)
        {
            if (w == null) return -1;

            int result = this.mainCanvas.Children.Add(w);

            w.RefreshLocation();//防止“组”的尺寸有问题。

            return result;
        }
        
        private bool IsCloseTo(double x, double y)
        {
            if (Math.Abs(x - y) <= 4) return true;
            return false;
        }

        /// <summary>
        /// 取此页面中所有文本块或矩形部件。刷新自动编号时需要用到此方法。
        /// 目前2012年6月25日的想法是：
        /// 只允许文本块支持自动编号。矩形已改为只用在正文。MainTitle/T1-T5均已改为文本块。
        /// </summary>
        /// <returns>不会返回null。</returns>
        public List<TextArea> GetAllTextAreaWidgets()
        {
            List<TextArea> list = new List<TextArea>();
            foreach (UIElement ue in this.Children)
            {
                Widgets.TextArea tw = ue as Widgets.TextArea;
                if (tw != null)
                {
                    list.Add(tw);
                    continue;
                }
            }
            return list;
        }

        /// <summary>
        /// 取此页面中所有部件。
        /// </summary>
        /// <param name="withOutArrowLineWidgets">不包含ArrowLineWidget。</param>
        /// <returns>不会返回null。</returns>
        public List<Widget> GetAllWidgets(bool withOutArrowLineWidgets = false)
        {
            List<Widget> list = new List<Widget>();
            foreach (UIElement ue in this.Children)
            {
                Widget w = ue as Widget;
                if (w != null)
                {
                    if (withOutArrowLineWidgets == false)
                    {
                        list.Add(w);
                    }
                    else
                    {
                        if (w is ArrowLineWidget) continue;
                        else list.Add(w);
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// ★对于线来说，格式化要考虑水平线、垂直线、左右正斜线。
        /// 
        /// 按住Shift键拖动鼠标时，要对鼠标指向的真实位置进行格式化。
        /// 
        /// 返回格式化后的相对终点，这个终点是根据真实终点与相对起点的相对关系来确定的，
        /// ——得到的结果总在以相对想点中中心画出的（虚拟的）水平线、垂直线、左右正斜线上。
        /// </summary>
        /// <param name="startPoint">相对起点。</param>
        /// <param name="realCurPoint">真实终点。</param>
        /// <returns>根据真实终点与相对起点的位置关系计算出来的相对终点（虚拟终点）。</returns>
        private Point GetFormatedLineMovingPoint(Point startPoint, Point realCurPoint)
        {
            double horizontalDistance = realCurPoint.X - startPoint.X;
            double verticalDistance = realCurPoint.Y - startPoint.Y;

            double absHD = Math.Abs(horizontalDistance);
            double absVD = Math.Abs(verticalDistance);

            if (absVD > absHD)
            {
                if (absVD > absHD * 2)
                {
                    realCurPoint = new Point(startPoint.X, realCurPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(realCurPoint, startPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y - (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 2:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y + (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 3:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y - (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 4:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                    startPoint.Y + (realCurPoint.X - startPoint.X));
                                break;
                            }
                    }
                }
            }
            else
            {
                if (absVD * 2 < absHD)
                {
                    realCurPoint = new Point(realCurPoint.X, startPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(realCurPoint, startPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y - (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 2:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y + (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 3:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                   startPoint.Y - (realCurPoint.X - startPoint.X));
                                break;
                            }
                        case 4:
                            {
                                realCurPoint = new Point(realCurPoint.X,
                                    startPoint.Y + (realCurPoint.X - startPoint.X));
                                break;
                            }
                    }
                }
            }

            return realCurPoint;
        }

        /// <summary>
        /// 以basePoint为基础坐标，画出四象限。
        /// 取出pt在哪个象限中。
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="basePoint"></param>
        /// <returns></returns>
        private int Getquadrant(Point pt, Point basePoint)
        {
            if (pt.X > basePoint.X)
            {
                if (pt.Y > basePoint.Y)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                if (pt.Y > basePoint.Y)
                {
                    return 3;
                }
                else
                {
                    return 2;
                }
            }
        }
        
        /// <summary>
        /// 刷新本页面中，与指定部件列表中的部件相关联的所有部件（线）的位置。
        /// </summary>
        /// <param name="widgets">要刷新的部件。这些部件及与它们关联的线都会刷新到它们定义的位置。</param>
        public void RefreshLinkedWidgetsLocation(List<Widget> widgets)
        {
            List<ILinkableLine> allPointLinkedWidgets = new List<ILinkableLine>();
            List<ILinkableLine> startPointLinkedWidgets = new List<ILinkableLine>();
            List<ILinkableLine> endPointLinkedWidgets = new List<ILinkableLine>();

            this.GetLinkdeLines(widgets,
                ref allPointLinkedWidgets,
                ref startPointLinkedWidgets,
                ref endPointLinkedWidgets);

            //还原操作之前选定的各部件的位置。
            foreach (Widgets.Widget w in widgets)
            {
                if (w is ILinkableLine == false)
                    w.RefreshLocation();
            }

            foreach (ILinkableLine linkableLine in allPointLinkedWidgets)
            {
                linkableLine.RefreshLocation();
            }

            foreach (ILinkableLine linkableLine in startPointLinkedWidgets)
            {
                linkableLine.RefreshLocation();
            }

            foreach (ILinkableLine linkableLine in endPointLinkedWidgets)
            {
                linkableLine.RefreshLocation();
            }
        }

        /// <summary>
        /// 刷新页脚位置。
        /// </summary>
        void baseCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.editArea.X = 46;
            this.editArea.Y = 36;
            double w = e.NewSize.Width - 92;
            double h = e.NewSize.Height - 72;
            this.editArea.Width = (w < 0 ? 0 : w);
            this.editArea.Height = (h < 0 ? 0 : h);

            RefreshPageSideRectanglesLocation();
            RefreshPageTitleLocation();

            Canvas.SetLeft(this.editorAdornerDecorator, this.editArea.X);
            Canvas.SetTop(this.editorAdornerDecorator, this.editArea.Y);
            this.editorAdornerDecorator.Width = this.editArea.Width;
            this.editorAdornerDecorator.Height = this.editArea.Height;
        }

        /// <summary>
        /// 根据xmlData的内容生成本编辑器中所有部件内容。
        /// </summary>
        public void Build()
        {
            if (this.xmlData == null)
                throw new NullReferenceException("PageEditor的xmlData节点为null！");

            XmlAttribute attrId = this.xmlData.GetAttribute(XmlTags.IdTag);
            if (attrId != null)
            {
                this.id = attrId.Value;
            }

            XmlAttribute attrPageTitle = this.xmlData.GetAttribute(XmlTags.PageTitleTag);
            if (attrPageTitle != null)
            {
                this.tbPageTitle.Text = attrPageTitle.Value;
            }

            XmlAttribute attrPageSize = this.xmlData.GetAttribute(XmlTags.PaperSizeTag);
            if (attrPageSize != null)
            {
                this.paperSize = PaperInfo.GetPaperInfo(attrPageSize.Value);//此方法会保证与Slide尺寸改名前的文档兼容。
            }
            else
            {
                this.paperSize = defPaperInfo;
            }

            XmlAttribute attrLongSideMultiple = this.xmlData.GetAttribute(XmlTags.PageLongSideMultipleTag);
            if (attrLongSideMultiple != null)
            {
                this.pageLongSideMultiple = int.Parse(attrLongSideMultiple.Value);
            }
            else
            {
                this.pageLongSideMultiple = 1;
            }

            XmlAttribute attrShortSideMultiple = this.xmlData.GetAttribute(XmlTags.PageShortSideMultipleTag);
            if (attrShortSideMultiple != null)
            {
                this.pageShortSideMultiple = int.Parse(attrShortSideMultiple.Value);
            }
            else
            {
                this.pageShortSideMultiple = 1;
            }

            XmlAttribute attrPageDirection = this.xmlData.GetAttribute(XmlTags.PaperDirectionTag);
            if (attrPageDirection != null)
            {
                this.PaperDirection = (Orientation)Enum.Parse(typeof(Orientation), attrPageDirection.Value);
            }

            XmlAttribute attrPageBackground = this.xmlData.GetAttribute(XmlTags.PageBackground);
            if (attrPageBackground != null)
            {
                this.pageBackground = Tools.BrushManager.GetBrushByEnglishName(attrPageBackground.Value);
                RefreshPageBackground();
            }

            //读入页眉区域底色。
            XmlAttribute attrPageFooterColor = this.xmlData.GetAttribute(XmlTags.PageRightSideBackColorTag);
            if (attrPageFooterColor != null)
            {
                this.pageRightSideBackColor = Tools.BrushManager.GetBrush(attrPageFooterColor.Value);
            }
            else
            {
                this.pageRightSideBackColor = Brushes.Transparent;
            }
            this.pageRightSideRectangle.Fill = this.pageRightSideBackColor;

            //读入页脚区域底色。
            XmlAttribute attrPageHeaderColor = this.xmlData.GetAttribute(XmlTags.PageLeftSideBackColorTag);
            if (attrPageHeaderColor != null)
            {
                this.pageLeftSideBackColor = Tools.BrushManager.GetBrush(attrPageHeaderColor.Value);
            }
            else
            {
                this.pageLeftSideBackColor = Brushes.Transparent;
            }
            this.pageLeftSideRectangle.Fill = this.pageLeftSideBackColor;

            //在《Lunar Concept》中没有这个属性，因为不需要。
            XmlAttribute attrAssistGridStroke = this.xmlData.GetAttribute(XmlTags.AssistGridStrokeTag);
            if(attrAssistGridStroke!= null)
            {
                this.assistGridStroke = Tools.BrushManager.GetBrush(attrAssistGridStroke.Value);
            }
            else
            {
                this.assistGridStroke = Brushes.Blue;
            }

            //读入Comment
            XmlAttribute attrCommentText = this.xmlData.GetAttribute(XmlTags.CommentTextTag);
            if (attrCommentText != null)
            {
                this.commentText = XmlTools.RestoreXmlChars(attrCommentText.Value);
            }

            RefreshPaperDirectionAndSize();

            //生成PageEditor中的内容。
            this.mainCanvas.Children.Clear();

            XmlNode wsetNode = this.WidgetSetNode;
            XmlNodeList widgetNodeList = wsetNode.SelectNodes(XmlTags.WidgetTag);

            foreach (XmlNode node in widgetNodeList)
            {
                Widgets.Widget w = Widgets.Widget.BuildWidget(this, node);
                this.mainCanvas.Children.Add(w);
            }

            XmlAttribute attrAssistGridForm = this.xmlData.GetAttribute(XmlTags.AssistGridFormTag);
            if (attrAssistGridForm != null)
            {
                this.AssistGridForm = (AssistGridForm)Enum.Parse(typeof(AssistGridForm), attrAssistGridForm.Value);
            }

            //baseCanvas_SizeChanged事件会处理。
            //RefreshPageHeaderAndFooterArea();
            //RefreshPageFooterLocation();
            //RefreshPageTitleLocation();
        }


        private AssistGridForm assistGridForm = AssistGridForm.Box;
        /// <summary>
        /// [读写]辅助线色彩。
        /// </summary>
        public Brush AssistGridStroke
        {
            get
            {
                return assistGridStroke;
            }

            set
            {
                assistGridStroke = value;
            }
        }
        /// <summary>
        /// [读写]是否显示风格线。默认只显示为Box。不随文档保存。
        /// </summary>
        public AssistGridForm AssistGridForm
        {
            get { return assistGridForm; }
            set
            {
                assistGridForm = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.AssistGridFormTag, assistGridForm.ToString());
                }
                RefreshAssistGridForm();
            }
        }


        /// <summary>
        /// 用于显示网格线的装饰器。使用DrawingBrush解决不了模糊问题。
        /// </summary>
        private PageEditAreaGridAdorner editAreaAdorner;

        /// <summary>
        /// 覆盖在EditAreaRectangle外的装饰层。用以填充网格图形装饰器。
        /// </summary>
        private AdornerDecorator editorAdornerDecorator;


        public void RefreshAssistGridForm()
        {
            this.editAreaAdorner.InvalidateVisual();
        }
        
        /// <summary>
        /// 取“自指定部件链接到其它可链接部件”的链接线。
        /// </summary>
        /// <param name="icw">指定部件。</param>
        /// <returns>如icw为null或icw的MasterPageEditor不是此编辑器，或icw不在此编辑器中，返回null。</returns>
        public List<Widgets.Interfaces.ILinkableLine> GetLinkedFromLines(Widgets.Interfaces.ICanBeLinkedWidget icw)
        {
            if (icw == null || icw.MasterEditor != this ||
                this.Children.Contains(icw as Widget) == false) return null;

            List<Widgets.Interfaces.ILinkableLine> linkedLines = new List<Widgets.Interfaces.ILinkableLine>();

            foreach (UIElement u in Children)
            {
                Widgets.Interfaces.ILinkableLine linkedLine = u as Widgets.Interfaces.ILinkableLine;
                if (linkedLine == null ||
                    (linkedLine.StartMasterId == string.Empty && linkedLine.EndMasterId == string.Empty)) continue;

                if (linkedLine.StartMasterId == icw.Id)
                {
                    if (linkedLines.Contains(linkedLine) == false)
                    {
                        linkedLines.Add(linkedLine);
                    }
                }
            }

            return linkedLines;
        }

        /// <summary>
        /// 取“链接到”指定部件的链接线。
        /// </summary>
        /// <param name="icw">指定部件。</param>
        /// <returns>如icw为null或icw的MasterPageEditor不是此编辑器，或icw不在此编辑器中，返回null。</returns>
        public List<Widgets.Interfaces.ILinkableLine> GetLinkedToLines(Widgets.Interfaces.ICanBeLinkedWidget icw)
        {
            if (icw == null || icw.MasterEditor != this ||
                   this.Children.Contains(icw as Widget) == false) return null;

            List<Widgets.Interfaces.ILinkableLine> linkedLines = new List<Widgets.Interfaces.ILinkableLine>();

            foreach (UIElement u in Children)
            {
                Widgets.Interfaces.ILinkableLine linkedLine = u as Widgets.Interfaces.ILinkableLine;
                if (linkedLine == null ||
                    (linkedLine.StartMasterId == string.Empty && linkedLine.EndMasterId == string.Empty)) continue;

                if (linkedLine.EndMasterId == icw.Id)
                {
                    if (linkedLines.Contains(linkedLine) == false)
                    {
                        linkedLines.Add(linkedLine);
                    }
                }
            }

            return linkedLines;
        }

        /// <summary>
        /// 取链接到指定部件的所有链接线。
        /// </summary>
        /// <param name="icw">指定部件。</param>
        /// <returns>如icw为null或icw的MasterPageEditor不是此编辑器，或icw不在此编辑器中，返回null。</returns>
        public List<Widgets.Interfaces.ILinkableLine> GetLinkedLines(Widgets.Interfaces.ICanBeLinkedWidget icw)
        {
            if (icw == null || icw.MasterEditor != this ||
                this.Children.Contains(icw as Widget) == false) return null;

            List<Widgets.Interfaces.ILinkableLine> linkedLines = new List<Widgets.Interfaces.ILinkableLine>();

            foreach (UIElement u in Children)
            {
                Widgets.Interfaces.ILinkableLine linkedLine = u as Widgets.Interfaces.ILinkableLine;
                if (linkedLine == null ||
                    (linkedLine.StartMasterId == string.Empty && linkedLine.EndMasterId == string.Empty)) continue;

                if (linkedLine.StartMasterId == icw.Id || linkedLine.EndMasterId == icw.Id)
                {
                    if (linkedLines.Contains(linkedLine) == false)
                    {
                        linkedLines.Add(linkedLine);
                    }
                }
            }

            return linkedLines;
        }

        /// <summary>
        /// 取任意一个端点被挂接到参数列表中某个Content部件的所有直线。
        /// </summary>
        public List<Widgets.Interfaces.ILinkableLine> GetLinkedLines(List<Widget> widgets)
        {
            if (widgets == null || widgets.Count <= 0) return null;

            List<Widgets.Interfaces.ILinkableLine> linkedLines = new List<Widgets.Interfaces.ILinkableLine>();

            foreach (UIElement u in Children)
            {
                Widgets.Interfaces.ILinkableLine linkedLine = u as Widgets.Interfaces.ILinkableLine;
                if (linkedLine == null ||
                    (linkedLine.StartMasterId == string.Empty && linkedLine.EndMasterId == string.Empty)) continue;

                foreach (Widget w in widgets)
                {
                    if (w is Widgets.Interfaces.ICanBeLinkedWidget == false) continue;

                    if (linkedLine.StartMasterId == w.Id || linkedLine.EndMasterId == w.Id)
                    {
                        if (linkedLines.Contains(linkedLine) == false)
                        {
                            linkedLines.Add(linkedLine);
                        }
                    }
                }
            }

            return linkedLines;
        }

        public void GetLinkdeLines(
            List<Widget> widgets,
            ref List<ILinkableLine> allPointsLinkedLines,
            ref List<ILinkableLine> startLinkedLines,
            ref List<ILinkableLine> endLinkedLines)
        {
            if (widgets == null || widgets.Count <= 0) return;
            if (allPointsLinkedLines == null || startLinkedLines == null || endLinkedLines == null) return;

            foreach (UIElement u in Children)
            {
                ILinkableLine linkedLine = u as ILinkableLine;
                if (linkedLine == null ||
                    (linkedLine.StartMasterId == string.Empty && linkedLine.EndMasterId == string.Empty)) continue;

                foreach (Widget w in widgets)
                {
                    if (w is ICanBeLinkedWidget == false) continue;

                    if (linkedLine.StartMasterId == w.Id)
                    {
                        if (startLinkedLines.Contains(linkedLine) == false)
                        {
                            startLinkedLines.Add(linkedLine);
                        }
                    }

                    if (linkedLine.EndMasterId == w.Id)
                    {
                        if (endLinkedLines.Contains(linkedLine) == false)
                        {
                            endLinkedLines.Add(linkedLine);
                        }
                    }
                }
            }

            for (int i1 = startLinkedLines.Count - 1; i1 >= 0; i1--)
            {
                ILinkableLine startLinkedLine = startLinkedLines[i1];

                for (int i2 = endLinkedLines.Count - 1; i2 >= 0; i2--)
                {
                    ILinkableLine endLinkedLine = endLinkedLines[i2];

                    if (startLinkedLine == endLinkedLine)
                    {
                        endLinkedLines.Remove(endLinkedLine);
                        startLinkedLines.Remove(startLinkedLine);
                        allPointsLinkedLines.Add(startLinkedLine);
                    }
                }
            }
        }

        /// <summary>
        /// 取当前页面中所有部件。
        /// </summary>
        /// <returns>不会返回null。而是返回空列表。</returns>
        public List<Widgets.Widget> GetListOfAllWidgets()
        {
            List<Widgets.Widget> widgetList = new List<Widgets.Widget>();

            foreach (UIElement ue in this.mainCanvas.Children)
            {
                Widgets.Widget w = ue as Widgets.Widget;
                if (w == null) continue;

                widgetList.Add(w);
            }

            return widgetList;
        }

        /// <summary>
        /// 根据ID找出Widget。
        /// </summary>
        /// <param name="id">要找的Widget的ID。</param>
        /// <returns>如果找不到，会返回null。</returns>
        public Widgets.Widget GetWidget(string id)
        {
            foreach (UIElement ue in this.mainCanvas.Children)
            {
                Widgets.Widget w = ue as Widgets.Widget;
                if (w == null) continue;

                if (w.Id == id) return w;
            }

            return null;
        }

        /// <summary>
        /// 取与指定矩形范围相交的部件集。
        /// 如果找不到，会返回一个列表而不是返回null。此时列表中没有成员。
        /// </summary>
        /// <param name="area">指定范围。</param>
        /// <param name="sortByTop">是否按顶边纵坐标排序。若为false，则按左边横坐标排序。</param>
        public List<Widgets.Widget> GetWidgetsInArea(Rect area, bool sortByTop)
        {
            List<Widgets.Widget> widgetList = new List<Widget>();
            if (area.Width <= 0 || area.Height <= 0) return widgetList;

            foreach (UIElement ue in this.Children)
            {
                Widgets.Widget w = ue as Widgets.Widget;
                if (w == null) continue;

                if (w.OuterRect.IntersectsWith(area))
                {
                    widgetList.Add(w);
                }
            }

            if (widgetList.Count > 0)
            {
                if (sortByTop)
                {
                    widgetList.Sort(new WidgetCenterYCompareClass());
                }
                else
                {
                    widgetList.Sort(new WidgetCenterXCompareClass());
                }
            }

            return widgetList;
        }
        
        /// <summary>
        /// [只写]设置PaperSize的值。
        /// </summary>
        public string PaperSizeText
        {
            set
            {
                this.PaperSize = PaperInfo.GetPaperInfo(value);
            }
        }

        private ThicknessConverter thicknessConverter = new ThicknessConverter();

        public ThicknessConverter ThickConverter
        {
            get
            {
                return thicknessConverter;
            }

            set
            {
                thicknessConverter = value;
            }
        }


        /// <summary>
        /// 在内部调用RefreshLinkedLines(ModifingItem<Action, ModifingInfo>,List<Widgets.Interfaces.ILinkableLine>)方法来完成任务。
        /// </summary>
        public void RefreshLinkedLines(ILinkableLine linkedLine)
        {
            if (linkedLine == null) return;
            List<ILinkableLine> linkedLines = new List<ILinkableLine>();
            linkedLines.Add(linkedLine);

            this.RefreshLinkedLines(linkedLines);
        }

        /// <summary>
        /// 刷新连接线的位置。
        /// </summary>
        /// <param name="startLinkedLines">要刷新位置的连接线列表。</param>
        public void RefreshLinkedLines(List<Widgets.Interfaces.ILinkableLine> linkedLines)
        {
            if (linkedLines == null || linkedLines.Count <= 0) return;

            foreach (Widgets.Interfaces.ILinkableLine linkedLine in linkedLines)
            {
                Widget startMaster = this.GetWidget(linkedLine.StartMasterId);
                Widget endMaster = this.GetWidget(linkedLine.EndMasterId);
                if (startMaster == null || endMaster == null) continue;//如果有一个已经被删除，则不进行位移。

                Rect startRect = new Rect(startMaster.TopLeft, startMaster.BottomRight);
                startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
                Rect endRect = new Rect(endMaster.TopLeft, endMaster.BottomRight);
                endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

                if (startRect.IntersectsWith(endRect) == false)
                {
                    Widgets.StraitLineWidget sLine = linkedLine as Widgets.StraitLineWidget;
                    if (sLine != null && this.Children.Contains(sLine))
                    {
                        Point newStartCenter = new Point(startRect.Left + (startRect.Width / 2), startRect.Top + (startRect.Height / 2));
                        Point newEndCenter = new Point(endRect.Left + (endRect.Width / 2), endRect.Top + (endRect.Height / 2));

                        if (sLine.EndLinkTo == Enums.LinkToPoint.Center && sLine.StartLinkTo == Enums.LinkToPoint.Center)
                        {
                            Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, newEndCenter);//注意这里互相以对方的中点为基准
                            Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, newStartCenter);

                            linkedLine.StartPoint = aptStart.Top;
                            linkedLine.EndPoint = aptEnd.Top;
                        }
                        else
                        {
                            if (sLine.StartLinkTo == Enums.LinkToPoint.Center)
                            {
                                //先求EndPoint
                                Point? endPoint = sLine.GetLinkedPoint(endRect, sLine.EndLinkTo);
                                if (endPoint != null && endPoint.HasValue)
                                {
                                    Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endPoint.Value);

                                    linkedLine.StartPoint = aptStart.Top;
                                    linkedLine.EndPoint = endPoint.Value;
                                }
                            }
                            else if (sLine.EndLinkTo == Enums.LinkToPoint.Center)
                            {
                                //先求StartPoint
                                Point? startPoint = sLine.GetLinkedPoint(startRect, sLine.StartLinkTo);
                                if (startPoint != null && startPoint.HasValue)
                                {
                                    Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startPoint.Value);

                                    linkedLine.StartPoint = startPoint.Value;
                                    linkedLine.EndPoint = aptEnd.Top;
                                }
                            }
                            else
                            {
                                Point? startPoint = sLine.GetLinkedPoint(startRect, sLine.StartLinkTo);
                                Point? endPoint = sLine.GetLinkedPoint(endRect, sLine.EndLinkTo);
                                if (startPoint != null && startPoint.HasValue && endPoint != null && endPoint.HasValue)
                                {
                                    linkedLine.StartPoint = startPoint.Value;
                                    linkedLine.EndPoint = endPoint.Value;
                                }
                            }
                        }
                    }

                    Widgets.BezierLineWidget bLine = linkedLine as Widgets.BezierLineWidget;
                    if (bLine != null && this.Children.Contains(bLine))
                    {
                        if (bLine.LineForm == Enums.BezierLineForms.MindMapLinkLine)
                        {
                            Point tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint;

                            Tools.ArrowPoints aptStart = bLine.GetMindLinePoints(ref startRect, ref endRect,
                                out tmpStartPoint, out tmpStartCPPoint,
                                out tmpEndCPPoint, out tmpEndPoint);

                            linkedLine.StartPoint = aptStart.ArrowRealTopPoint;
                            bLine.StartCPPoint = tmpStartCPPoint;
                            bLine.EndCPPoint = tmpEndCPPoint;
                            linkedLine.EndPoint = tmpEndPoint;
                        }
                        else
                        {
                            Point newStartCenter = new Point(startRect.Left + (startRect.Width / 2), startRect.Top + (startRect.Height / 2));
                            Point newEndCenter = new Point(endRect.Left + (endRect.Width / 2), endRect.Top + (endRect.Height / 2));

                            Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, bLine.StartCPPoint);//注意这里互相以对方的中点为基准
                            Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, bLine.EndCPPoint);

                            linkedLine.StartPoint = aptStart.Top;
                            linkedLine.EndPoint = aptEnd.Top;
                        }
                    }

                    Widgets.PolyLineWidget pLine = linkedLine as Widgets.PolyLineWidget;
                    if (pLine != null && this.Children.Contains(pLine))
                    {
                        switch (pLine.LineForm)
                        {
                            case Enums.PolyLineForms.BigFishBone:
                                {
                                    #region 大鱼骨线
                                    Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                                    if (startCenter.Y >= endRect.Top && startCenter.Y <= endRect.Bottom) break;

                                    Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                                    Point resultStartPoint;
                                    Point resultEndPoint;
                                    Point centerPoint;

                                    if (endCenter.X > startCenter.X)
                                    {
                                        resultStartPoint = new Point(startRect.Right, startCenter.Y);

                                        if (endCenter.Y > startCenter.Y)
                                        {
                                            resultEndPoint = new Point(endCenter.X, endRect.Top);
                                            centerPoint = new Point(resultEndPoint.X - Math.Abs(resultEndPoint.Y - startCenter.Y) / Math.Sqrt(3),
                                                startCenter.Y);

                                            if (centerPoint.X < startRect.Right) break;//空间不够。
                                        }
                                        else
                                        {
                                            resultEndPoint = new Point(endCenter.X, endRect.Bottom);
                                            centerPoint = new Point(resultEndPoint.X - Math.Abs(resultEndPoint.Y - startCenter.Y) / Math.Sqrt(3),
                                                startCenter.Y);

                                            if (centerPoint.X < startRect.Right) break;//空间不够。
                                        }
                                    }
                                    else
                                    {
                                        resultStartPoint = new Point(startRect.Left, startCenter.Y);

                                        if (endCenter.Y > startCenter.Y)
                                        {
                                            resultEndPoint = new Point(endCenter.X, endRect.Top);
                                            centerPoint = new Point(resultEndPoint.X + Math.Abs(resultEndPoint.Y - startCenter.Y) / Math.Sqrt(3),
                                                startCenter.Y);

                                            if (centerPoint.X > startRect.Left) break;//空间不够。
                                        }
                                        else
                                        {
                                            resultEndPoint = new Point(endCenter.X, endRect.Bottom);
                                            centerPoint = new Point(resultEndPoint.X + Math.Abs(resultEndPoint.Y - startCenter.Y) / Math.Sqrt(3),
                                                startCenter.Y);

                                            if (centerPoint.X > startRect.Left) break;//空间不够。
                                        }
                                    }

                                    resultStartPoint = pLine.FormatPoint(resultStartPoint);
                                    resultEndPoint = pLine.FormatPoint(resultEndPoint);
                                    centerPoint = pLine.FormatPoint(centerPoint);

                                    linkedLine.StartPoint = resultStartPoint;
                                    linkedLine.EndPoint = resultEndPoint;

                                    Point resultCPPoint = new Point(resultStartPoint.X + (resultEndPoint.X - resultStartPoint.X) / 2,
                                        resultStartPoint.Y + (resultEndPoint.Y - resultStartPoint.Y) / 2);
                                    pLine.CenterCPPoint = resultCPPoint;
                                    #endregion

                                    break;
                                }
                            case Enums.PolyLineForms.MediumFishBone:
                                {
                                    #region 中鱼骨线
                                    double padding = pLine.WidgetLineWidth;
                                    endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

                                    Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                                    Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                                    //if (startCenter.Y >= endRect.Top && startCenter.Y <= endRect.Bottom) return false;//中骨只显示横线

                                    Point resultStartPoint;
                                    Point resultEndPoint;
                                    Point startCPPoint;
                                    Point endCPPoint;
                                    Point endBasePoint;

                                    double d = Math.Sqrt(3);

                                    if (endCenter.X > startCenter.X)
                                    {
                                        resultStartPoint = new Point(startRect.Right, startCenter.Y);

                                        if (endCenter.Y > startCenter.Y)
                                        {
                                            endBasePoint = endRect.BottomLeft;
                                            endCPPoint = new Point(endBasePoint.X - endRect.Height / d, endBasePoint.Y - endRect.Height);
                                            resultEndPoint = new Point(endRect.Right, endCPPoint.Y);
                                            startCPPoint = new Point(endRect.Left - Math.Abs(endRect.Bottom - startCenter.Y) / d, startCenter.Y);

                                            //if (startCPPoint.X < startRect.Right) return false;//空间不够。//中骨只显示横线
                                        }
                                        else
                                        {
                                            endBasePoint = endRect.TopLeft;
                                            endCPPoint = new Point(endBasePoint.X - endRect.Height / d, endBasePoint.Y + endRect.Height);
                                            resultEndPoint = new Point(endRect.Right, endCPPoint.Y);
                                            startCPPoint = new Point(endRect.Left - Math.Abs(endRect.Top - startCenter.Y) / d, startCenter.Y);

                                            //if (startCPPoint.X < startRect.Right) return false;//空间不够。//中骨只显示横线
                                        }
                                    }
                                    else
                                    {
                                        resultStartPoint = new Point(startRect.Left, startCenter.Y);

                                        if (endCenter.Y > startCenter.Y)
                                        {
                                            endBasePoint = endRect.BottomRight;
                                            endCPPoint = new Point(endBasePoint.X + endRect.Height / d, endBasePoint.Y - endRect.Height);
                                            resultEndPoint = new Point(endRect.Left, endCPPoint.Y);
                                            startCPPoint = new Point(endRect.Right + Math.Abs(endRect.Bottom - startCenter.Y) / d, startCenter.Y);

                                            //if (startCPPoint.X > startRect.Left) return false;//空间不够。//中骨只显示横线
                                        }
                                        else
                                        {
                                            endBasePoint = endRect.TopRight;
                                            endCPPoint = new Point(endBasePoint.X + endRect.Height / d, endBasePoint.Y + endRect.Height);
                                            resultEndPoint = new Point(endRect.Left, endCPPoint.Y);
                                            startCPPoint = new Point(endRect.Right + Math.Abs(endRect.Top - startCenter.Y) / d, startCenter.Y);

                                            //if (startCPPoint.X > startRect.Left) return false;//空间不够。//中骨只显示横线
                                        }
                                    }

                                    resultStartPoint = pLine.FormatPoint(resultStartPoint);
                                    resultEndPoint = pLine.FormatPoint(resultEndPoint);
                                    startCPPoint = pLine.FormatPoint(startCPPoint);

                                    linkedLine.StartPoint = resultStartPoint;

                                    linkedLine.EndPoint = resultEndPoint;

                                    Point resultCPPoint = new Point(resultStartPoint.X + (resultEndPoint.X - resultStartPoint.X) / 2,
                                        resultStartPoint.Y + (resultEndPoint.Y - resultStartPoint.Y) / 2);

                                    pLine.CenterCPPoint = resultCPPoint;

                                    #endregion

                                    break;
                                }
                            case Enums.PolyLineForms.CLine:
                                {
                                    #region C形线

                                    double padding = pLine.WidgetLineWidth;
                                    endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

                                    Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                                    Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                                    Point resultStartPoint;
                                    Point resultEndPoint;
                                    Point startBasePoint;
                                    Point endBasePoint;
                                    Point cpPoint;

                                    switch (pLine.Direction)
                                    {
                                        case Orientation.Horizontal:
                                            {
                                                if (startCenter.Y <= endCenter.Y)//中段线在顶部
                                                {
                                                    double top = Math.Min(startRect.Top - 20, endRect.Top - 20);
                                                    resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Top));
                                                    resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Top));
                                                    startBasePoint = pLine.FormatPoint(new Point(startCenter.X, top));
                                                    endBasePoint = pLine.FormatPoint(new Point(endCenter.X, top));
                                                    cpPoint = pLine.FormatPoint(new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2, startBasePoint.Y));
                                                }
                                                else//中段线在底部
                                                {
                                                    double bottom = Math.Max(startRect.Bottom + 20, endRect.Bottom + 20);
                                                    resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Bottom));
                                                    resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Bottom));
                                                    startBasePoint = pLine.FormatPoint(new Point(startCenter.X, bottom));
                                                    endBasePoint = pLine.FormatPoint(new Point(endCenter.X, bottom));
                                                    cpPoint = pLine.FormatPoint(new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2, startBasePoint.Y));
                                                }
                                                break;
                                            }
                                        default:
                                            {
                                                if (startCenter.X <= endCenter.X)//中段线在左侧
                                                {
                                                    double left = Math.Min(startRect.Left - 20, endRect.Left - 20);
                                                    resultStartPoint = pLine.FormatPoint(new Point(startRect.Left, startCenter.Y));
                                                    resultEndPoint = pLine.FormatPoint(new Point(endRect.Left, endCenter.Y));
                                                    startBasePoint = pLine.FormatPoint(new Point(left, startCenter.Y));
                                                    endBasePoint = pLine.FormatPoint(new Point(left, endCenter.Y));
                                                    cpPoint = pLine.FormatPoint(new Point(startBasePoint.X, startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2));
                                                }
                                                else//中段线在右侧
                                                {
                                                    double right = Math.Max(startRect.Right + 20, endRect.Right + 20);
                                                    resultStartPoint = pLine.FormatPoint(new Point(startRect.Right, startCenter.Y));
                                                    resultEndPoint = pLine.FormatPoint(new Point(endRect.Right, endCenter.Y));
                                                    startBasePoint = pLine.FormatPoint(new Point(right, startCenter.Y));
                                                    endBasePoint = pLine.FormatPoint(new Point(right, endCenter.Y));
                                                    cpPoint = pLine.FormatPoint(new Point(startBasePoint.X, startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2));
                                                }
                                                break;
                                            }
                                    }

                                    linkedLine.StartPoint = resultStartPoint;
                                    linkedLine.EndPoint = resultEndPoint;

                                    Point resultCPPoint = new Point(resultStartPoint.X + (resultEndPoint.X - resultStartPoint.X) / 2,
                                        resultStartPoint.Y + (resultEndPoint.Y - resultStartPoint.Y) / 2);
                                    pLine.CenterCPPoint = resultCPPoint;

                                    #endregion

                                    break;
                                }
                            case Enums.PolyLineForms.LLine:
                                {
                                    #region L形线

                                    double padding = pLine.WidgetLineWidth;
                                    endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

                                    Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
                                    Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

                                    Point resultStartPoint;
                                    Point resultEndPoint;

                                    switch (pLine.Direction)
                                    {
                                        case Orientation.Horizontal:
                                            {
                                                if (startCenter.X <= endCenter.X)//EndRect在右侧
                                                {
                                                    if (startCenter.Y <= endCenter.Y)//End在右下
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startRect.Right, startCenter.Y));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Top));
                                                    }
                                                    else//End在右上
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startRect.Right, startCenter.Y));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Bottom));
                                                    }
                                                }
                                                else//EndRect在左侧
                                                {
                                                    if (startCenter.Y <= endCenter.Y)//End在左下
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startRect.Left, startCenter.Y));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Top));
                                                    }
                                                    else//End在左上
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startRect.Left, startCenter.Y));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endCenter.X, endRect.Bottom));
                                                    }
                                                }

                                                break;
                                            }
                                        default:
                                            {
                                                if (startCenter.X <= endCenter.X)//EndRect在右侧
                                                {
                                                    if (startCenter.Y <= endCenter.Y)//End在右下
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Bottom));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endRect.Left, endCenter.Y));
                                                    }
                                                    else//End在右上
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Top));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endRect.Left, endCenter.Y));
                                                    }
                                                }
                                                else//EndRect在左侧
                                                {
                                                    if (startCenter.Y <= endCenter.Y)//End在左下
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Bottom));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endRect.Right, endCenter.Y));
                                                    }
                                                    else//End在左上
                                                    {
                                                        resultStartPoint = pLine.FormatPoint(new Point(startCenter.X, startRect.Top));
                                                        resultEndPoint = pLine.FormatPoint(new Point(endRect.Right, endCenter.Y));
                                                    }
                                                }

                                                break;
                                            }
                                    }

                                    linkedLine.StartPoint = resultStartPoint;
                                    linkedLine.EndPoint = resultEndPoint;

                                    Point resultCPPoint = new Point(resultStartPoint.X + (resultEndPoint.X - resultStartPoint.X) / 2,
                                        resultStartPoint.Y + (resultEndPoint.Y - resultStartPoint.Y) / 2);
                                    pLine.CenterCPPoint = resultCPPoint;
                                    #endregion

                                    break;
                                }
                            default:
                                {
                                    #region 普通折线连接线

                                    Point newStartCenter = new Point(startRect.Left + (startRect.Width / 2), startRect.Top + (startRect.Height / 2));
                                    Point newEndCenter = new Point(endRect.Left + (endRect.Width / 2), endRect.Top + (endRect.Height / 2));

                                    Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, newEndCenter);//注意这里互相以对方的中点为基准
                                    Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, newStartCenter);

                                    Point resultStartPt;
                                    Point resultEndPt;

                                    //两个矩形不相交，又分这样几种情况：
                                    //１.如果两个矩形之间水平方向上有部分重叠；——此时折线中段只能纵向。取左、右边中点。
                                    //２.如果两个矩形之间垂直方向上有部分重叠；——此时折线中段只能横向。取顶、底边中点。
                                    //３.如果两个矩形之间没有任何重叠；此时由折线自身决定中段线的方向。据此决定取哪两个边的中点。

                                    if ((startRect.Bottom >= endRect.Top && startRect.Bottom <= endRect.Bottom) ||
                                        (startRect.Top >= endRect.Top && startRect.Top <= endRect.Bottom) ||
                                        (endRect.Bottom >= startRect.Top && endRect.Bottom <= startRect.Bottom) ||
                                        (endRect.Top >= startRect.Top && endRect.Top <= startRect.Bottom))
                                    {
                                        //水平方向上至少有部分重叠：
                                        if (aptStart.Top.X < newStartCenter.X)
                                        {
                                            resultStartPt = new Point(startRect.Left - 2, newStartCenter.Y);
                                        }
                                        else
                                        {
                                            resultStartPt = new Point(startRect.Right + 2, newStartCenter.Y);
                                        }

                                        if (aptEnd.Top.X < newEndCenter.X)
                                        {
                                            resultEndPt = new Point(endRect.Left - 2, newEndCenter.Y);
                                        }
                                        else
                                        {
                                            resultEndPt = new Point(endRect.Right + 2, newEndCenter.Y);
                                        }

                                        if (pLine.Direction != Orientation.Vertical)
                                        {
                                            pLine.Direction = Orientation.Vertical;
                                        }
                                    }
                                    else
                                    {
                                        if ((startRect.Left >= endRect.Left && startRect.Left <= endRect.Right) ||
                                            (startRect.Right >= endRect.Left && startRect.Right <= endRect.Right) ||
                                            (endRect.Left >= startRect.Left && endRect.Left <= startRect.Right) ||
                                            (endRect.Right >= startRect.Left && endRect.Right <= startRect.Right))
                                        {
                                            //垂直方向至少有部分重叠：
                                            if (aptStart.Top.Y < newStartCenter.Y)
                                            {
                                                resultStartPt = new Point(newStartCenter.X, startRect.Top - 2);
                                            }
                                            else
                                            {
                                                resultStartPt = new Point(newStartCenter.X, startRect.Bottom + 2);
                                            }

                                            if (aptEnd.Top.Y < newEndCenter.Y)
                                            {
                                                resultEndPt = new Point(newEndCenter.X, endRect.Top - 2);
                                            }
                                            else
                                            {
                                                resultEndPt = new Point(newEndCenter.X, endRect.Bottom + 2);
                                            }

                                            if (pLine.Direction != Orientation.Horizontal)
                                            {
                                                pLine.Direction = Orientation.Horizontal;
                                            }
                                        }
                                        else
                                        {
                                            //没有任何重叠：
                                            if (pLine.Direction == Orientation.Horizontal)
                                            {
                                                if (newEndCenter.Y > newStartCenter.Y)
                                                {
                                                    resultStartPt = new Point(newStartCenter.X, startRect.Bottom + 2);
                                                    resultEndPt = new Point(newEndCenter.X, endRect.Top - 2);
                                                }
                                                else
                                                {
                                                    resultStartPt = new Point(newStartCenter.X, startRect.Top - 2);
                                                    resultEndPt = new Point(newEndCenter.X, endRect.Bottom + 2);
                                                }
                                            }
                                            else
                                            {
                                                if (newEndCenter.X > newStartCenter.X)
                                                {
                                                    resultStartPt = new Point(startRect.Right + 2, newStartCenter.Y);
                                                    resultEndPt = new Point(endRect.Left - 2, newEndCenter.Y);
                                                }
                                                else
                                                {
                                                    resultStartPt = new Point(startRect.Left - 2, newStartCenter.Y);
                                                    resultEndPt = new Point(endRect.Right + 2, newEndCenter.Y);
                                                }
                                            }
                                        }
                                    }

                                    linkedLine.StartPoint = resultStartPt;
                                    linkedLine.EndPoint = resultEndPt;

                                    Point resultCPPoint = new Point(resultStartPt.X + (resultEndPt.X - resultStartPt.X) / 2,
                                        resultStartPt.Y + (resultEndPt.Y - resultStartPt.Y) / 2);
                                    pLine.CenterCPPoint = resultCPPoint;
                                    #endregion

                                    break;
                                }
                        }
                    }
                }
                else
                {
                    Point newStartCenter = new Point(startRect.Left + (startRect.Width / 2), startRect.Top + (startRect.Height / 2));
                    Point newEndCenter = new Point(endRect.Left + (endRect.Width / 2), endRect.Top + (endRect.Height / 2));

                    Point center = new Point(newStartCenter.X + (newEndCenter.X - newStartCenter.X) / 2,
                        newStartCenter.Y + (newEndCenter.Y - newStartCenter.Y) / 2);

                    linkedLine.StartPoint = center;
                    linkedLine.EndPoint = center;
                }
            }
        }

        /// <summary>
        /// PageBackground属性值改变时会调用此方法刷新部件的背景色。
        /// ——亦可根据需要调用。
        /// ——默认直接改变mainBorder的背景色。派生类可自行定义行为。
        /// </summary>
        public void RefreshPageBackground()
        {
            if (this.baseCanvas != null)
                this.baseCanvas.Background = pageBackground;
        }

        /// <summary>
        /// 根据“PaperDirection”和“PaperSize”刷新页面尺寸。最终尺寸还会乘以指定的长边扩展倍数、短边扩展倍数，扩展倍数默认为1（即不扩展）。
        /// </summary>
        private void RefreshPaperDirectionAndSize()
        {
            switch (paperDirection)
            {
                case Orientation.Horizontal:
                    {
                        baseCanvas.Width = paperSize.LongSideWPFUnit * this.pageLongSideMultiple;
                        baseCanvas.Height = paperSize.ShortSideWPFUnit * this.pageShortSideMultiple;
                        break;
                    }
                case Orientation.Vertical:
                    {
                        baseCanvas.Width = paperSize.ShortSideWPFUnit * this.pageShortSideMultiple;
                        baseCanvas.Height = paperSize.LongSideWPFUnit * this.pageLongSideMultiple;
                        break;
                    }
            }
        }

        /// <summary>
        /// 刷新各部件尺寸、位置，以防出错（例如“组”的尺寸就会出错。
        /// 
        /// ★此方法必须在此页面已被添加到页面管理器后调用，
        /// 且页面管理器所在的主窗口已经显示，否则无效。
        /// 刷新内部各部件的位置。
        /// </summary>
        public void RefreshWidgetsLocation()
        {
            //this.InvalidateArrange();
            //this.UpdateLayout();

            foreach (UIElement ueWidget in this.Children)
            {
                Widgets.Widget w = ueWidget as Widgets.Widget;
                if (w == null) continue;

                w.RefreshLocation();
            }
        }
        
        /// <summary>
        /// 刷新页面标题文本块的位置。
        /// </summary>
        public void RefreshPageTitleLocation()
        {
            this.tbPageTitle.InvalidateArrange();
            this.tbPageTitle.UpdateLayout();
            Size size = this.tbPageTitle.RenderSize;

            Canvas.SetLeft(this.tbPageTitle, this.baseCanvas.ActualWidth - size.Width - 20);
            Canvas.SetTop(this.tbPageTitle, 20);
        }

        /// <summary>
        /// 刷新页眉页脚背景矩形的位置、尺寸。
        /// </summary>
        public void RefreshPageSideRectanglesLocation()
        {
            this.pageLeftSideRectangle.Width = this.editArea.Left;
            this.pageLeftSideRectangle.Height = this.editArea.Height + 1;
            Canvas.SetTop(this.pageLeftSideRectangle, this.editArea.Top - 1);

            this.pageRightSideRectangle.Width = Math.Max(0, this.baseCanvas.ActualWidth - this.editArea.Right);
            this.pageRightSideRectangle.Height = this.editArea.Height + 1;
            Canvas.SetLeft(this.pageRightSideRectangle, this.editArea.Right);
            Canvas.SetTop(this.pageRightSideRectangle, this.editArea.Top - 1);
        }

        /// <summary>
        /// 设置“页码”框中的文本。
        /// ——因为绑定比较复杂，而且稳定性未必好，因此直接提供一个方法。
        /// </summary>
        /// <param name="paginationText">新页码文本。</param>
        public void RefreshPagination(string paginationText)
        {
            if (paginationText == null)
            {
                this.pagination.Text = string.Empty;
            }
            else
            {
                this.pagination.Text = paginationText;
            }
        }

        /// <summary>
        /// 从当前页面中移除指定的部件。
        /// ★本方法不会移除XmlData，需要手工另行编写代码。
        /// </summary>
        /// <param name="sw">要移除的部件。</param>
        public void RemoveWidget(Widgets.Widget w)
        {
            if (w == null) return;
            if (this.mainCanvas.Children.Contains(w) == false) return;

            this.mainCanvas.Children.Remove(w);
        }

        #endregion

        #region 事件=========================================================================================================

        public void OpenContextMenu()
        {
            if (this.mainCanvas.ContextMenu != null)
            {
                this.mainCanvas.ContextMenu.IsOpen = true;
            }
        }
        
        public event EventHandler<MainSelectedWidgetChangedEventArgs> MainSelectedWidgetChanged;

        protected void OnMainSelectedWidgetChanged(object sender, MainSelectedWidgetChangedEventArgs e)
        {
            if (MainSelectedWidgetChanged != null)
            {
                MainSelectedWidgetChanged(this, e);
            }
        }
        
        #endregion

    }

    public class MainSelectedWidgetChangedEventArgs : EventArgs
    {
        public MainSelectedWidgetChangedEventArgs(Widget newMainSelectedWidget)
        {
            this.newMainSelectedWidget = newMainSelectedWidget;
        }

        private Widget newMainSelectedWidget = null;

        public Widget NewMainSelectedWidget
        {
            get { return newMainSelectedWidget; }
        }
    }
}
